/*
    kOTF Open Trace Format - a library for generating execution traces.
    Copyright 2010 Daniel K. O.

    kOTF is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kOTF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with kOTF.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <iomanip>

#include <kotf/Reader.hpp>


using namespace std;
using namespace kotf;



void printStreamBegin(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "StreamBegin"
         << sess.streams.at(e.stream.id).name
         << ":" << e.stream.id
         << " tag=" << e.stream.tag;
    if (e.stream.parent != InvalidId)
        cout << " (" << sess.streams.at(e.stream.parent).name << " : "
             << e.stream.parent << ")";
}

void printStreamEnd(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "StreamEnd"
         << sess.streams.at(e.stream.id).name
         << ":" << e.stream.id
         << " tag=" << e.stream.tag;
}

void printEnterState(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "EnterState"
         << sess.states[e.state.id]
         << ":" << e.state.id
         << " tag=" << e.state.tag;
}

void printLeaveState(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "LeaveState"
         << sess.states[e.state.id]
         << ":" << e.state.id
         << " tag=" << e.state.tag;
}

void printCounter(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "Counter"
         << sess.counters[e.counter.id]
         << ":" << e.counter.id
         << " = " << e.counter.value
         << " tag=" << e.counter.tag;
}

void printSend(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "Send"
         << sess.channels[e.message.chan]
         << ":" << e.message.chan
         << " len=" << e.message.len
         << " tag=" << e.message.tag;
}

void printBroadcast(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "Broadcast"
         << sess.channels[e.message.chan]
         << ":" << e.message.chan
         << " len=" << e.message.len
         << " tag=" << e.message.tag;
}

void printRecv(const Event& e, SessionReader& sess)
{
    cout << setw(12) << left << "Recv"
         << sess.channels[e.message.chan]
         << ":" << e.message.chan
         << " len=" << e.message.len
         << " tag=" << e.message.tag;
}


void printEvent(const Event& e, SessionReader& sess)
{
    typedef void (*PrintFunc)(const Event& e, SessionReader& sess);
    static PrintFunc funcs[8] = {
        printStreamBegin,
        printStreamEnd,
        printEnterState,
        printLeaveState,
        printCounter,
        printSend,
        printBroadcast,
        printRecv
    };
    if (unsigned(e.base.type) > 7) {
        cout << "Invalid event type: " << hex << e.base.type << dec << '\n';
        return;
    }

    cout << setw(10) << right << e.base.timestamp << " ";
    funcs[e.base.type](e, sess);
    cout << '\n';
}

int main(int argc, char **argv)
{
    if (argc != 2) {
        cerr << "Argument: session name" << endl;
        return 1;
    }

    try {
        SessionReader sess(argv[1]);
        
        cout << "Session Started: " << sess.startTime << '\n';

        for (SessionReader::iterator i=sess.streams.begin(); i!=sess.streams.end(); ++i) {
            cout << "Stream " << i->second->name << ":" << i->first << '\n';

            for (StreamReader::const_iterator j=i->second->begin(); j!=i->second->end(); ++j) {
                printEvent(*j, sess);
            }
        }

        cout << "Session Finished: " << sess.finishTime << endl;

        return 0;
    }
    catch (Error &e) {
        cerr << "Error: " << e.what() << endl;
        return 1;
    }
}

